import sys
import cv2
from pyzbar import pyzbar
from datetime import datetime
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, 
                              QHBoxLayout, QPushButton, QLabel, QFileDialog, 
                              QListWidget, QSplitter, QFrame)
from PySide6.QtCore import QThread, Signal, Qt, QTimer
from PySide6.QtGui import QImage, QPixmap

class VideoProcessingThread(QThread):
    """视频处理线程，避免UI卡顿"""
    frame_ready = Signal(QImage)  # 发送处理后的帧
    barcode_detected = Signal(dict)  # 发送检测到的条形码信息
    
    def __init__(self, video_path):
        super().__init__()
        self.video_path = video_path
        self.running = False
        self.paused = False
        self.skip_frames = 5
        self.resize_scale = 0.7
        self.recognized_barcodes = set()

    def run(self):
        self.running = True
        cap = cv2.VideoCapture(self.video_path)
        
        if not cap.isOpened():
            print(f"无法打开视频文件: {self.video_path}")
            self.running = False
            return
        
        frame_count = 0
        
        while self.running:
            if self.paused:
                self.msleep(50)
                continue
                
            ret, frame = cap.read()
            if not ret:
                break  # 视频结束
            
            frame_count += 1
            
            # 跳帧处理
            process_frame = (frame_count % self.skip_frames == 0)
            
            # 降低分辨率
            if self.resize_scale != 1.0:
                frame = cv2.resize(frame, (0, 0), fx=self.resize_scale, fy=self.resize_scale)
            
            # 检测条形码（只在指定帧进行）
            if process_frame:
                frame, barcodes = self.detect_barcodes(frame)
                for barcode in barcodes:
                    if barcode["data"] not in self.recognized_barcodes:
                        self.recognized_barcodes.add(barcode["data"])
                        self.barcode_detected.emit(barcode)
            
            # 转换为QImage并发送到UI
            rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            h, w, ch = rgb_image.shape
            bytes_per_line = ch * w
            q_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)
            self.frame_ready.emit(q_image)
            
            # 控制处理速度
            self.msleep(30)
        
        cap.release()
        self.running = False

    def detect_barcodes(self, frame):
        detected_barcodes = []
        gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        barcodes = pyzbar.decode(gray)
        
        for barcode in barcodes:
            (x, y, w, h) = barcode.rect
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
            
            barcode_data = barcode.data.decode("utf-8")
            barcode_type = barcode.type
            current_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
            
            text = f"{barcode_data} ({barcode_type})"
            cv2.putText(frame, text, (x, y - 10), 
                       cv2.FONT_HERSHEY_SIMPLEX, 0.5, (0, 255, 0), 2)
            
            detected_barcodes.append({
                "data": barcode_data,
                "type": barcode_type,
                "time": current_time
            })
        
        return frame, detected_barcodes
    
    def toggle_pause(self):
        self.paused = not self.paused
    
    def stop(self):
        self.running = False
        self.wait()

class BarcodeScannerApp(QMainWindow):
    """条形码扫描器主窗口"""
    def __init__(self):
        super().__init__()
        self.setWindowTitle("条形码识别器")
        self.setGeometry(100, 100, 1000, 700)
        
        self.video_thread = None
        self.init_ui()
    
    def init_ui(self):
        # 主部件和布局
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QVBoxLayout(central_widget)
        
        # 顶部控制按钮
        control_layout = QHBoxLayout()
        
        self.open_btn = QPushButton("打开视频文件")
        self.open_btn.clicked.connect(self.open_video)
        
        self.play_pause_btn = QPushButton("播放/暂停")
        self.play_pause_btn.clicked.connect(self.play_pause)
        self.play_pause_btn.setEnabled(False)
        
        self.skip_label = QLabel("跳帧数: 5")
        
        self.decrease_skip_btn = QPushButton("-")
        self.decrease_skip_btn.clicked.connect(lambda: self.change_skip_frames(-1))
        self.decrease_skip_btn.setEnabled(False)
        
        self.increase_skip_btn = QPushButton("+")
        self.increase_skip_btn.clicked.connect(lambda: self.change_skip_frames(1))
        self.increase_skip_btn.setEnabled(False)
        
        control_layout.addWidget(self.open_btn)
        control_layout.addWidget(self.play_pause_btn)
        control_layout.addWidget(self.skip_label)
        control_layout.addWidget(self.decrease_skip_btn)
        control_layout.addWidget(self.increase_skip_btn)
        control_layout.addStretch()
        
        # 中间视频和结果显示区域
        splitter = QSplitter(Qt.Horizontal)
        
        # 视频显示区域
        self.video_frame = QFrame()
        self.video_frame.setFrameShape(QFrame.StyledPanel)
        video_layout = QVBoxLayout(self.video_frame)
        
        self.video_label = QLabel("请打开视频文件")
        self.video_label.setAlignment(Qt.AlignCenter)
        self.video_label.setMinimumSize(400, 300)
        video_layout.addWidget(self.video_label)
        
        # 结果显示区域
        self.results_frame = QFrame()
        self.results_frame.setFrameShape(QFrame.StyledPanel)
        results_layout = QVBoxLayout(self.results_frame)
        
        self.results_label = QLabel("识别结果:")
        self.results_list = QListWidget()
        self.results_list.setMinimumSize(300, 300)
        
        results_layout.addWidget(self.results_label)
        results_layout.addWidget(self.results_list)
        
        splitter.addWidget(self.video_frame)
        splitter.addWidget(self.results_frame)
        splitter.setSizes([600, 400])  # 设置初始大小比例
        
        # 添加到主布局
        main_layout.addLayout(control_layout)
        main_layout.addWidget(splitter)
    
    def open_video(self):
        """打开视频文件对话框"""
        file_path, _ = QFileDialog.getOpenFileName(
            self, "选择视频文件", "", "视频文件 (*.mp4 *.avi *.mov *.mkv)"
        )
        
        if file_path:
            # 如果已有运行的线程，先停止
            if self.video_thread and self.video_thread.isRunning():
                self.video_thread.stop()
            
            # 创建并启动新的视频处理线程
            self.video_thread = VideoProcessingThread(file_path)
            self.video_thread.frame_ready.connect(self.update_video_frame)
            self.video_thread.barcode_detected.connect(self.add_barcode_result)
            self.video_thread.start()
            
            # 更新UI状态
            self.play_pause_btn.setEnabled(True)
            self.decrease_skip_btn.setEnabled(True)
            self.increase_skip_btn.setEnabled(True)
            self.skip_label.setText(f"跳帧数: {self.video_thread.skip_frames}")
            self.results_list.clear()
    
    def update_video_frame(self, q_image):
        """更新视频显示帧"""
        pixmap = QPixmap.fromImage(q_image)
        # 保持比例缩放
        scaled_pixmap = pixmap.scaled(
            self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation
        )
        self.video_label.setPixmap(scaled_pixmap)
    
    def add_barcode_result(self, barcode_info):
        """添加条形码识别结果到列表"""
        result_text = f"[{barcode_info['time']}] {barcode_info['data']} ({barcode_info['type']})"
        self.results_list.addItem(result_text)
        # 滚动到最新项
        self.results_list.scrollToBottom()
    
    def play_pause(self):
        """播放/暂停视频"""
        if self.video_thread:
            self.video_thread.toggle_pause()
    
    def change_skip_frames(self, delta):
        """调整跳帧数"""
        if self.video_thread:
            new_skip = self.video_thread.skip_frames + delta
            if new_skip >= 1:  # 确保跳帧数至少为1
                self.video_thread.skip_frames = new_skip
                self.skip_label.setText(f"跳帧数: {self.video_thread.skip_frames}")
    
    def closeEvent(self, event):
        """窗口关闭时停止线程"""
        if self.video_thread and self.video_thread.isRunning():
            self.video_thread.stop()
        event.accept()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = BarcodeScannerApp()
    window.show()
    sys.exit(app.exec())
